package com.hardson.toolkit.swing.datepicker;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.util.Calendar;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JSpinner.NumberEditor;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.border.EtchedBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class DatePickerPanel extends ImagePanel implements ChangeListener, ActionListener, MouseListener {

	public static int PICKERTYPE_DATEANDTIME = 1;// 显示日期和时间

	public static int PICKERTYPE_DATEONLY = 2;// 只显示日期

	public static int PICKERTYPE_TIMEONLY = 3;// 只显示时间

	public static int ACTIONTYPE_CONFIRM = 1;// 确认

	public static int ACTIONTYPE_RESET = 2;// 重置

	public static int ACTIONTYPE_CANCEL = 3;// 取消

	Color backGroundColor = Color.GRAY; // 底色
	// 月历表格配色----------------//

	Color palletTableColor = Color.WHITE; // 日历表底色

	Color todayBackColor = Color.ORANGE; // 今天背景色

	Color weekFontColor = Color.BLUE; // 星期文字色

	Color dateFontColor = Color.BLACK; // 日期文字色

	Color saturdayFontColor = new Color(64, 128, 128); // 周六文字色

	Color sundayFontColor = Color.RED; // 周日文字色

	// 控制条配色------------------//
	Color controlLineColor = new Color(217, 236, 255);; // 控制条底色

	Color controlTextColor = Color.BLUE; // 控制条标签文字色

	Color rbFontColor = Color.WHITE; // RoundBox文字色

	Color rbBorderColor = Color.RED; // RoundBox边框色

	Color rbButtonColor = Color.PINK; // RoundBox按钮色

	Color rbBtFontColor = Color.RED; // RoundBox按钮文字色

	private int pickerType = PICKERTYPE_DATEANDTIME;

	private Image headImg = null;

	private Calendar selectedCal;

	private IPickerCallBack parent;

	int startYear = 1900; // 默认【最小】显示年份

	int lastYear = 2030; // 默认【最大】显示年份

	private Point startPoint;

	private JButton[][] daysButton = new JButton[6][7];

	public DatePickerPanel(final IPickerCallBack parent, final Image headImg, final Image bgImg) {
		this(parent, headImg, bgImg, Calendar.getInstance(), PICKERTYPE_DATEANDTIME);
	}

	public DatePickerPanel(final IPickerCallBack parent, final Image headImg, final Image bgImg,
			final Calendar selectedCal) {
		this(parent, headImg, bgImg, selectedCal, PICKERTYPE_DATEANDTIME);
	}

	/**
	 * @wbp.parser.constructor
	 */
	public DatePickerPanel(final IPickerCallBack parent, final Image headImg, final Image bgImg,
			final Calendar selectedCal, final int pickerType) {
		this.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
		//this.setFont(Fonts.SONG16);
		this.selectedCal = (selectedCal == null) ? Calendar.getInstance() : selectedCal;
		this.headImg = headImg;
		this.bgImage = bgImg;
		this.parent = parent;
		this.pickerType = pickerType;

		this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

		this.pnlYearMonthTime = new JPanel();
		this.pnlYearMonthTime.setPreferredSize(new Dimension(10, 60));
		this.add(this.pnlYearMonthTime);

		this.pnlDateWeek = new JPanel();
		this.pnlDateWeek.setPreferredSize(new Dimension(10, 200));
		this.add(this.pnlDateWeek);

		this.pnlOperateBar = new JPanel();
		this.add(this.pnlOperateBar);

		this.initYearMonthTimePanel();
		this.initWeekAndDayPanal();
		this.initOperatePanel();

		if (this.pickerType == PICKERTYPE_DATEONLY) {
			this.hourLabel.setVisible(false);
			this.hourSpin.setVisible(false);
			this.minuteLabel.setVisible(false);
			this.minuteSpin.setVisible(false);
			this.secondSpin.setVisible(false);
		}
		if (this.pickerType == PICKERTYPE_TIMEONLY) {
			this.yearLabel.setVisible(false);
			this.yearSpin.setVisible(false);
			this.monthLabel.setVisible(false);
			this.monthSpin.setVisible(false);
			this.pnlDateWeek.setVisible(false);
		}

		this.flushWeekAndDay();
	}

	private void initYearMonthTimePanel() {
		Calendar c = this.selectedCal;
		int currentYear = c.get(Calendar.YEAR);
		int currentMonth = c.get(Calendar.MONTH) + 1;
		int currentHour = c.get(Calendar.HOUR_OF_DAY);
		int currentMinute = c.get(Calendar.MINUTE);
		int currentSecond = c.get(Calendar.SECOND);
		this.pnlYearMonthTime.addMouseMotionListener(new MouseMotionAdapter() {
			@Override
			public void mouseDragged(final MouseEvent e) {
				Point p = e.getPoint();
				int moveX = p.x - DatePickerPanel.this.startPoint.x;
				int moveY = p.y - DatePickerPanel.this.startPoint.y;
				Point loc = ((Container) DatePickerPanel.this.parent).getLocation();
				Point newPoint = new Point(loc.x + moveX, loc.y + moveY);
				((Container) DatePickerPanel.this.parent).setLocation(newPoint);
			}
		});
		this.pnlYearMonthTime.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(final MouseEvent e) {
				DatePickerPanel.this.startPoint = e.getPoint();
			}
		});
		this.pnlYearMonthTime.setLayout(new BoxLayout(this.pnlYearMonthTime, BoxLayout.X_AXIS));

		this.glue = Box.createGlue();
		this.pnlYearMonthTime.add(this.glue);

		this.yearSpin = new JSpinner(new SpinnerNumberModel(currentYear, this.startYear, this.lastYear, 1));
		this.yearSpin.setPreferredSize(new Dimension(60, 25));
		this.yearSpin.setName("Year");
		//this.yearSpin.setFont(this.getFont());
		NumberEditor ne_yearSpin = new JSpinner.NumberEditor(this.yearSpin, "####");
		this.yearSpin.setEditor(ne_yearSpin);
		this.yearSpin.setMaximumSize(new Dimension(150, 25));
		this.pnlYearMonthTime.add(this.yearSpin);

		this.yearLabel = new JLabel("\u5E74");
		this.yearLabel.setForeground(this.controlTextColor);
		this.pnlYearMonthTime.add(this.yearLabel);

		this.monthSpin = new JSpinner(new SpinnerNumberModel(currentMonth, 1, 12, 1));
		this.monthSpin.setPreferredSize(new Dimension(45, 25));
		this.monthSpin.setName("Month");
		//this.monthSpin.setFont(this.getFont());
		this.monthSpin.setMaximumSize(new Dimension(100, 25));
		this.pnlYearMonthTime.add(this.monthSpin);

		this.monthLabel = new JLabel("\u6708");
		this.monthLabel.setForeground(this.controlTextColor);
		this.pnlYearMonthTime.add(this.monthLabel);

		this.horizontalStrut = Box.createHorizontalStrut(10);
		this.pnlYearMonthTime.add(this.horizontalStrut);

		this.hourSpin = new JSpinner(new SpinnerNumberModel(currentHour, 0, 23, 1));
		this.hourSpin.setPreferredSize(new Dimension(45, 25));
		this.hourSpin.setMaximumSize(new Dimension(100, 25));
		this.hourSpin.setName("Hour");
		//this.hourSpin.setFont(this.getFont());
		this.pnlYearMonthTime.add(this.hourSpin);

		this.hourLabel = new JLabel(":");
		this.hourLabel.setForeground(this.controlTextColor);
		this.pnlYearMonthTime.add(this.hourLabel);

		this.minuteSpin = new JSpinner(new SpinnerNumberModel(currentMinute, 0, 59, 1));
		this.minuteSpin.setPreferredSize(new Dimension(45, 25));
		this.minuteSpin.setName("Minute");
		//this.minuteSpin.setFont(this.getFont());
		this.minuteSpin.setMaximumSize(new Dimension(100, 25));
		this.pnlYearMonthTime.add(this.minuteSpin);

		this.minuteLabel = new JLabel(":");
		this.minuteLabel.setForeground(this.controlTextColor);
		this.pnlYearMonthTime.add(this.minuteLabel);

		this.secondSpin = new JSpinner(new SpinnerNumberModel(currentSecond, 0, 59, 1));
		this.secondSpin.setPreferredSize(new Dimension(45, 25));
		this.secondSpin.setName("Second");
		//this.secondSpin.setFont(this.getFont());
		this.secondSpin.setMaximumSize(new Dimension(100, 25));
		this.pnlYearMonthTime.add(this.secondSpin);

		this.glue_1 = Box.createGlue();
		this.pnlYearMonthTime.add(this.glue_1);
		this.pnlYearMonthTime.setBackground(this.controlLineColor);

		this.yearSpin.addChangeListener(this);
		this.monthSpin.addChangeListener(this);
		this.hourSpin.addChangeListener(this);
		this.secondSpin.addChangeListener(this);
		this.minuteSpin.addChangeListener(this);

		if (this.headImg != null) {
			this.pnlYearMonthTime.setOpaque(false);
		}
	}

	private void initWeekAndDayPanal() {
		String colname[] = { "日", "一", "二", "三", "四", "五", "六" };
		// 设置固定字体，以免调用环境改变影响界面美观
		//	this.pnlDateWeek.setFont(new Font("宋体", Font.PLAIN, 12));
		this.pnlDateWeek.setLayout(new GridLayout(7, 7));
		this.pnlDateWeek.setBackground(Color.WHITE);

		for (int i = 0; i < 7; i++) {
			JLabel cell = new JLabel(colname[i]);
			//cell.setFont(this.getFont());
			cell.setHorizontalAlignment(SwingConstants.CENTER);
			if (i == 0) {
				cell.setForeground(this.sundayFontColor);
			} else if (i == 6) {
				cell.setForeground(this.saturdayFontColor);
			} else {
				cell.setForeground(this.weekFontColor);
			}
			this.pnlDateWeek.add(cell);
		}

		int actionCommandId = 0;
		for (int i = 0; i < 6; i++) {
			for (int j = 0; j < 7; j++) {
				JButton numberButton = new JButton("");//new TransparentButton("",false);
				numberButton.setMargin(new Insets(5, 13, 0, 0));
				numberButton.setBorder(BorderFactory.createEmptyBorder(2, 1, 2, 1));
				//numberButton.setFont(this.getFont());
				numberButton.setHorizontalAlignment(SwingConstants.CENTER);
				numberButton.setActionCommand(String.valueOf(actionCommandId));
				numberButton.addActionListener(this);
				numberButton.setBackground(this.palletTableColor);
				numberButton.setForeground(this.dateFontColor);
				if (j == 0) {
					numberButton.setForeground(this.sundayFontColor);
				} else if (j == 6) {
					numberButton.setForeground(this.saturdayFontColor);
				}
				numberButton.addMouseListener(this);
				//numberButton.setOpaque(false);
				this.daysButton[i][j] = numberButton;
				this.pnlDateWeek.add(numberButton);
				actionCommandId++;
			}
		}

		if (this.bgImage != null) {
			this.pnlDateWeek.setOpaque(false);
		}
	}

	private void initOperatePanel() {
		this.pnlOperateBar.setPreferredSize(new Dimension(10, 60));
		this.pnlOperateBar.setBackground(this.controlLineColor);
		this.btnConfirm = new JButton("\u786E\u5B9A");//("\u786E\u5B9A", false);//"确定"
		this.btnConfirm.setMaximumSize(new Dimension(58, 30));
		this.btnConfirm.setMinimumSize(new Dimension(58, 30));
		//this.btnConfirm.setFont(this.getFont());
		this.btnConfirm.setMargin(new Insets(13, 16, 0, 0));
		this.btnConfirm.setPreferredSize(new Dimension(75, 30));
		this.btnConfirm.setBackground(this.controlLineColor);
		this.btnConfirm.setOpaque(false);
		this.btnConfirm.setBorder(null);
		this.btnConfirm.addMouseListener(this);
		this.btnConfirm.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent e) {
				DatePickerPanel.this.confirm();
			}
		});
		this.pnlOperateBar.setLayout(new BoxLayout(this.pnlOperateBar, BoxLayout.X_AXIS));

		this.glue_2 = Box.createGlue();
		this.pnlOperateBar.add(this.glue_2);
		this.pnlOperateBar.add(this.btnConfirm);

		this.btnReset = new JButton("\u6E05\u7A7A");//"清空"
		this.btnReset.setMaximumSize(new Dimension(58, 30));
		this.btnReset.setMinimumSize(new Dimension(58, 30));
		//this.btnReset.setFont(this.getFont());
		this.btnReset.setMargin(new Insets(13, 16, 0, 0));
		this.btnReset.setPreferredSize(new Dimension(75, 30));
		this.btnReset.setBackground(this.controlLineColor);
		this.btnReset.setOpaque(false);
		this.btnReset.setBorder(null);
		this.btnReset.addMouseListener(this);
		this.btnReset.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent e) {
				DatePickerPanel.this.reset();
			}
		});
		this.pnlOperateBar.add(this.btnReset);

		this.btnCancel = new JButton("\u53D6\u6D88");//"取消");
		this.btnCancel.setMaximumSize(new Dimension(58, 30));
		this.btnCancel.setMinimumSize(new Dimension(58, 30));
		//this.btnCancel.setFont(this.getFont());
		this.btnCancel.setMargin(new Insets(13, 16, 0, 0));
		this.btnCancel.setPreferredSize(new Dimension(75, 30));
		this.btnCancel.setBackground(this.controlLineColor);
		this.btnCancel.setOpaque(false);
		this.btnCancel.setBorder(null);
		this.btnCancel.addMouseListener(this);
		this.btnCancel.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent e) {
				DatePickerPanel.this.cancel();
			}
		});
		this.pnlOperateBar.add(this.btnCancel);

		this.glue_3 = Box.createGlue();
		this.pnlOperateBar.add(this.glue_3);
	}

	private void dayColorUpdate(final boolean oldDay) {
		Calendar c = (Calendar) this.selectedCal.clone();
		int day = c.get(Calendar.DAY_OF_MONTH);
		c.set(Calendar.DAY_OF_MONTH, 1);
		int actionCommandId = day - 2 + c.get(Calendar.DAY_OF_WEEK);
		int i = actionCommandId / 7;
		int j = actionCommandId % 7;
		if (oldDay) {
			// daysButton[i][j].setForeground(dateFontColor);
			this.daysButton[i][j].setBackground(this.palletTableColor);
			//((TransparentButton) this.daysButton[i][j]).setFillRec(false);
		} else {
			//((TransparentButton) this.daysButton[i][j]).setFillRec(true);
			this.daysButton[i][j].setBackground(this.todayBackColor);
		}
	}

	public Calendar getCalendar() {
		return this.selectedCal;
	}

	public int getSelectedYear() {
		return ((Integer) this.yearSpin.getValue()).intValue();
	}

	public int getSelectedMonth() {
		return ((Integer) this.monthSpin.getValue()).intValue();
	}

	public int getSelectedHour() {
		return ((Integer) this.hourSpin.getValue()).intValue();
	}

	public int getSelectedMinute() {
		return ((Integer) this.minuteSpin.getValue()).intValue();
	}

	public int getSelectedSecond() {
		return ((Integer) this.secondSpin.getValue()).intValue();
	}

	@Override
	public void stateChanged(final ChangeEvent e) {
		JSpinner source = (JSpinner) e.getSource();
		String name = source.getName();
		if (name.equals("Hour")) {
			this.selectedCal.set(Calendar.HOUR_OF_DAY, this.getSelectedHour());
			return;
		}
		if (name.equals("Minute")) {
			this.selectedCal.set(Calendar.MINUTE, this.getSelectedMinute());
			return;
		}
		if (name.equals("Second")) {
			this.selectedCal.set(Calendar.SECOND, this.getSelectedSecond());
			return;
		}
		this.dayColorUpdate(true);

		if (name.equals("Year")) {
			this.selectedCal.set(Calendar.YEAR, this.getSelectedYear());
		} else if (name.equals("Month")) {
			this.selectedCal.set(Calendar.MONTH, this.getSelectedMonth() - 1);
		}
		this.flushWeekAndDay();

	}

	private void flushWeekAndDay() {
		Calendar c = (Calendar) this.selectedCal.clone();
		c.set(Calendar.DAY_OF_MONTH, 1);
		int maxDayNo = c.getActualMaximum(Calendar.DAY_OF_MONTH);
		int dayNo = 2 - c.get(Calendar.DAY_OF_WEEK);
		for (int i = 0; i < 6; i++) {
			for (int j = 0; j < 7; j++) {
				String s = "";
				if (dayNo >= 1 && dayNo <= maxDayNo) {
					s = String.valueOf(dayNo);
				}
				this.daysButton[i][j].setText(s);
				dayNo++;
			}
		}
		this.dayColorUpdate(false);
	}

	private void confirm() {
		this.parent.recall(ACTIONTYPE_CONFIRM);
	}

	private void cancel() {
		this.parent.recall(ACTIONTYPE_CANCEL);
	}

	private void reset() {
		this.parent.recall(ACTIONTYPE_RESET);
	}

	@Override
	public void actionPerformed(final ActionEvent e) {
		JButton source = (JButton) e.getSource();
		if (source.getText().length() == 0) {
			return;
		}
		this.dayColorUpdate(true);
		//((TransparentButton) source).setFillRec(true);
		source.setBackground(this.todayBackColor);
		int newDay = Integer.parseInt(source.getText());
		this.selectedCal.set(Calendar.DAY_OF_MONTH, newDay);
		this.confirm();
	}

	@Override
	public void mouseClicked(final MouseEvent e) {
	}

	@Override
	public void mousePressed(final MouseEvent e) {
	}

	@Override
	public void mouseReleased(final MouseEvent e) {
	}

	@Override
	public void mouseEntered(final MouseEvent e) {
		JButton source = (JButton) e.getSource();
		source.setCursor(Cursor.getPredefinedCursor(java.awt.Cursor.HAND_CURSOR));
		source.setBorder(BorderFactory.createEtchedBorder(javax.swing.border.EtchedBorder.LOWERED));
		source.repaint();
	}

	@Override
	public void mouseExited(final MouseEvent e) {
		JButton source = (JButton) e.getSource();
		source.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		source.setBorder(null);
		source.repaint();
	}

	@Override
	public void setFont(final Font font) {
		super.setFont(font);
		this.refreshFont(this, font);
	}

	private void refreshFont(final Container parent, final Font font) {
		for (Component comp : parent.getComponents()) {
			if (comp instanceof JSpinner || comp instanceof JButton || comp instanceof JLabel) {
				comp.setFont(font);
			} else {
				this.refreshFont((Container) comp, font);
			}
		}
	}

	private static final long serialVersionUID = 1L;

	private JPanel pnlYearMonthTime;

	private JPanel pnlDateWeek;

	private JPanel pnlOperateBar;

	private JSpinner yearSpin;

	private JSpinner monthSpin;

	private JSpinner hourSpin;

	private JSpinner minuteSpin;

	private JSpinner secondSpin;

	private JButton btnConfirm;

	private JButton btnReset;

	private JButton btnCancel;

	private JLabel yearLabel;

	private JLabel monthLabel;

	private JLabel hourLabel;

	private JLabel minuteLabel;

	private Component glue;

	private Component glue_1;

	private Component horizontalStrut;

	private Component glue_2;

	private Component glue_3;

}
